﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Media3D;
using System.Diagnostics;

namespace Hotel.UI.Utils
{
    public class MouseZoomMoveTool
    {
        private UIElement element;
        private Point dragStartPoint;
        private System.Windows.Media.Matrix dragMatrix;

        public MouseZoomMoveTool(UIElement element)
        {
            this.element = element;

            DependencyObject d = element;
            while (d != null)
            {
                d = VisualTreeHelper.GetParent(d);
                if (d is System.Windows.Controls.Control parent)
                {
                    if (parent.Background is null)
                    {
                        parent.Background = Brushes.Transparent;
                    }

                    parent.MouseWheel += Control_MouseWheel;
                    parent.MouseLeftButtonDown += Control_MouseLeftButtonDown;
                    break;
                }
            }
        }

        private void Control_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            var parent = (System.Windows.Controls.Control)sender;
            if (parent.CaptureMouse())
            {
                parent.MouseMove += Control_MouseMove;
                parent.MouseLeftButtonUp += Control_MouseLeftButtonUp;

                this.dragStartPoint = e.GetPosition(parent);
                this.dragMatrix = GetMatrixTransform().Matrix;
                e.Handled = true;
            }
        }


        private void Control_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
        {
            var control = (System.Windows.Controls.Control)sender;
            MatrixTransform mt = GetMatrixTransform();

            var p2 = e.GetPosition(control);

            var matrix = dragMatrix;

            var x = (p2.X - dragStartPoint.X);// * matrix.M11;
            var y = (p2.Y - dragStartPoint.Y);// * matrix.M11;

            matrix.Translate(x, y);

            mt.Matrix = matrix;

            e.Handled = true;
        }

        private void Control_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            var control = (System.Windows.Controls.Control)sender;
            control.ReleaseMouseCapture();
            control.MouseMove -= Control_MouseMove;
            control.MouseUp -= Control_MouseLeftButtonUp;

            e.Handled = true;
        }

        private void Control_MouseWheel(object sender, System.Windows.Input.MouseWheelEventArgs me)
        {
            var control = (System.Windows.Controls.Control)sender;
            if (control.IsMouseCaptured)
            {
                return;
            }
            MatrixTransform mt = GetMatrixTransform();

            var p = me.GetPosition(this.element);

            var matrix = mt.Matrix;
            double scaleCurrentX = matrix.M11;
            double scaleCurrentY = matrix.M22;

            double scaleDelta = (me.Delta < 0) ? 0.95 : 1.05;

            var p2 = matrix.Transform(new Point(0, 0));
            var centerX = scaleCurrentX * p.X + p2.X;
            var centerY = scaleCurrentY * p.Y + p2.Y;

            matrix.ScaleAt(scaleDelta, scaleDelta, centerX, centerY);
            mt.Matrix = matrix;

            me.Handled = true;
        }


        private MatrixTransform GetMatrixTransform()
        {
            if (!(element.RenderTransform is MatrixTransform mt) || mt.IsFrozen)
            {
                mt = new MatrixTransform();
                element.RenderTransform = mt;
            }
            return mt;
        }

        /// <summary>
        /// 适合窗体大小
        /// </summary>
        public void ReSet()
        {
            var masterImage = this.element as Image;
            if (masterImage?.Source == null)
                return;
            Debug.WriteLine($"ReSet,ActualWidth:{masterImage.ActualWidth},ActualHeight:{masterImage.ActualHeight},Source.Width:{masterImage.Source.Width},Source.Height:{masterImage.Source.Height}");

            var AW = masterImage.ActualWidth;
            var AH = masterImage.ActualHeight;

            var OW = masterImage.Source.Width;
            var OH = masterImage.Source.Height;

            MatrixTransform mt = GetMatrixTransform();

            mt.Matrix = new Matrix();
            //var matrix = mt.Matrix;
            //matrix.M11 = 1;
            //matrix.M22 = 1;
            //matrix.OffsetX = 0;
            //matrix.OffsetY = 0;
            ////matrix.Invert(); // 反转矩阵
            //mt.Matrix = matrix;

        }

        /// <summary>
        /// 中心点显示原图
        /// </summary>
        public void ShowOriginalImage()
        {
            var masterImage = this.element as Image;
            if (masterImage?.Source == null)
                return;
            var AW = masterImage.ActualWidth;
            var AH = masterImage.ActualHeight;
            var OW = masterImage.Source.Width;
            var OH = masterImage.Source.Height;
            Debug.WriteLine($"ShowOriginalImage,ActualWidth:{masterImage.ActualWidth},ActualHeight:{masterImage.ActualHeight},Source.Width:{masterImage.Source.Width},Source.Height:{masterImage.Source.Height}");
            var r1 = OW / AW;
            var r2 = OH / AH;

            MatrixTransform mt = GetMatrixTransform();
            var matrix = mt.Matrix;
            matrix.M11 = OW / AW;
            matrix.M22 = OW / AW;
            matrix.OffsetX = (AW - OW) / 2;
            matrix.OffsetY = (AH - OH) / 2;
            matrix.M12 = 0;
            matrix.M21 = 0;
            mt.Matrix = matrix;
        }

        /// <summary>
        /// 缩小
        /// </summary>
        /// <param name="zoom">倍数</param>
        public void ZoomOut(double zoom = 0.25)
        {
            var masterImage = this.element as Image;
            if (masterImage?.Source == null)
                return;
            var AW = masterImage.ActualWidth;
            var AH = masterImage.ActualHeight;
            var OW = masterImage.Source.Width;
            var OH = masterImage.Source.Height;
            Debug.WriteLine($"ZoomOut,ActualWidth:{masterImage.ActualWidth},ActualHeight:{masterImage.ActualHeight},Source.Width:{masterImage.Source.Width},Source.Height:{masterImage.Source.Height}");
            MatrixTransform mt = GetMatrixTransform();
            var matrix = mt.Matrix;
            if (masterImage.ActualWidth * Math.Abs(matrix.M11) / 2 < 30
                || masterImage.ActualHeight * Math.Abs(matrix.M22) / 2 < 30
                //|| Math.Abs(matrix.M22) <= zoom
                //|| Math.Abs(matrix.M11) <= zoom
                )
                return;
            double scaleX = 1 - zoom;
            double scaleY = 1 - zoom;
            //if (matrix.M11 <= 0)
            //{
            //    scaleX = zoom - 1;
            //    // matrix.OffsetX -= masterImage.ActualWidth * zoom / 2;
            //}
            //else
            //{
            //    scaleX = 1 - zoom;
            //    //matrix.OffsetX += masterImage.ActualWidth * zoom / 2;
            //}
            //if (matrix.M22 <= 0)
            //{
            //    scaleY = zoom - 1;
            //    // matrix.OffsetY -= masterImage.ActualHeight * zoom / 2;
            //}
            //else
            //{
            //    scaleY = 1 - zoom;
            //    // matrix.OffsetY += masterImage.ActualHeight * zoom / 2;
            //}
            var center = new Point(AW / 2, AH / 2);
            Point centerReal = matrix.Transform(center);
            matrix.ScaleAt(scaleX, scaleY, centerReal.X, centerReal.Y);

            mt.Matrix = matrix;
        }
        /// <summary>
        /// 放大
        /// </summary>
        /// <param name="zoom">倍数</param>
        public void ZoomIn(double zoom = 0.25)
        {
            var masterImage = this.element as Image;
            if (masterImage?.Source == null)
                return;
            var AW = masterImage.ActualWidth;
            var AH = masterImage.ActualHeight;
            var OW = masterImage.Source.Width;
            var OH = masterImage.Source.Height;
            Debug.WriteLine($"ZoomIn,ActualWidth:{masterImage.ActualWidth},ActualHeight:{masterImage.ActualHeight},Source.Width:{masterImage.Source.Width},Source.Height:{masterImage.Source.Height}");
            MatrixTransform mt = GetMatrixTransform();
            var matrix = mt.Matrix;
            double scaleX = 1 + zoom;
            double scaleY = 1 + zoom;
            //if (matrix.M11 <= 0)
            //{
            //    scaleX = 1 + zoom;
            //    //  matrix.OffsetX += masterImage.ActualWidth * zoom / 2;
            //}
            //else
            //{
            //    scaleX = 1 + zoom;
            //    // matrix.OffsetX -= masterImage.ActualWidth * zoom / 2;
            //}
            //if (matrix.M22 <= 0)
            //{
            //    scaleY = -1 - zoom;
            //    // matrix.OffsetY += masterImage.ActualHeight * zoom / 2;
            //}
            //else
            //{
            //    scaleY = 1 + zoom;
            //    // matrix.OffsetY -= masterImage.ActualHeight * zoom / 2;
            //}

            var center = new Point(AW / 2, AH / 2);
            Point centerReal = matrix.Transform(center);
            matrix.ScaleAt(scaleX, scaleY, centerReal.X, centerReal.Y);

            mt.Matrix = matrix;
        }


        /// <summary>
        /// 水平翻转
        /// </summary>
        public void HorizontalReverse()
        {
            var masterImage = this.element as Image;
            if (masterImage?.Source == null)
                return;
            var AW = masterImage.ActualWidth;
            var AH = masterImage.ActualHeight;
            var OW = masterImage.Source.Width;
            var OH = masterImage.Source.Height;
            Debug.WriteLine($"HorizontalReverse,ActualWidth:{masterImage.ActualWidth},ActualHeight:{masterImage.ActualHeight},Source.Width:{masterImage.Source.Width},Source.Height:{masterImage.Source.Height}");
            MatrixTransform mt = GetMatrixTransform();
            var matrix = mt.Matrix;
            var center = new Point(AW / 2, AH / 2);
            Point centerReal = matrix.Transform(center);

            matrix.ScaleAt(-1, 1, centerReal.X, centerReal.Y);
            //var offSetX = masterImage.ActualWidth * matrix.M11;
            //matrix.M11 = -matrix.M11;
            //matrix.OffsetX += offSetX;
            mt.Matrix = matrix;
        }

        /// <summary>
        /// 垂直翻转
        /// </summary>
        public void VerticalReverse()
        {
            var masterImage = this.element as Image;
            if (masterImage?.Source == null)
                return;
            var AW = masterImage.ActualWidth;
            var AH = masterImage.ActualHeight;
            var OW = masterImage.Source.Width;
            var OH = masterImage.Source.Height;
            Debug.WriteLine($"VerticalReverse,ActualWidth:{masterImage.ActualWidth},ActualHeight:{masterImage.ActualHeight},Source.Width:{masterImage.Source.Width},Source.Height:{masterImage.Source.Height}");
            MatrixTransform mt = GetMatrixTransform();
            var matrix = mt.Matrix;
            var offSetY = masterImage.ActualHeight * matrix.M22;
            //matrix.M22 = -matrix.M22;
            //matrix.OffsetY += offSetY;
            var center = new Point(AW / 2, AH / 2);
            Point centerReal = matrix.Transform(center);

            matrix.ScaleAt(1, -1, centerReal.X, centerReal.Y);
            mt.Matrix = matrix;
        }
        /// <summary>
        /// (以图像中心点)顺时针旋转
        /// </summary>
        /// <param name="angle">角度</param>
        public void Rotate(double angle = 90)
        {
            var masterImage = this.element as Image;
            if (masterImage?.Source == null)
                return;
            var AW = masterImage.ActualWidth;
            var AH = masterImage.ActualHeight;
            var OW = masterImage.Source.Width;
            var OH = masterImage.Source.Height;
            Debug.WriteLine($"Rotate,ActualWidth:{masterImage.ActualWidth},ActualHeight:{masterImage.ActualHeight},Source.Width:{masterImage.Source.Width},Source.Height:{masterImage.Source.Height}");

            MatrixTransform mt = GetMatrixTransform();
            var matrix = mt.Matrix;
            var p = new Point(0, 0);
            var center = new Point(AW / 2, AH / 2);
            Point centerReal = matrix.Transform(center);

            double num = Math.Sin(angle);
            double num2 = Math.Cos(angle);
            //double offsetX = centerX * (1.0 - num2) + centerY * num;
            //double offsetY = centerY * (1.0 - num2) - centerX * num;

            var X = centerReal.X;
            var Y = centerReal.Y;
            Debug.WriteLine($"Rotate,{X},{Y},ActualWidth:{masterImage.ActualWidth},ActualHeight:{masterImage.ActualHeight},Source.Width:{masterImage.Source.Width},Source.Height:{masterImage.Source.Height}");

            angle %= 360.0;

            matrix.RotateAt(angle, X, Y);
            mt.Matrix = matrix;
        }
    }
}
